/*
Copyright (C) 2009-2011 Xanadu Development Team

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; version 2
of the License.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
*/

#include "scriptstring.h"
#include "AngelScriptEngine.h"
#include <iostream>
#include <assert.h>
#include "../client/NPCsScriptsData.h"
#include "../client/NPCsQuestsData.h"
#include "../client/PortalsData.h"
#include "../client/ReactorScriptsData.h"
#include "../server/Reactor.h"
#include "../server/Event.h"
#include "../net/world/Party.h"
#include "../net/world/Guild.h"
#include "../server/Player.h"
#include "../server/Players.h"
#include "../server/PlayerInventory.h"
#include "../server/PlayerNPC.h"
#include "../server/Map.h"
#include "../server/Maps.h"
#include "../server/Mob.h"
#include "../client/MapPortalData.h"
#include "../client/ChannelEventsScriptsData.h"
#include "../server/Channel.h"
#include "../server/Quest.h"
#include "../server/Skill.h"

asIScriptEngine* AngelScriptEngine::pScriptEngine;

const int tr = 1;
const int fa = 0;
const int asEQUIP = EQUIP;
const int asUSE = USE;
const int asSETUP= SETUP;
const int asETC = ETC;
const int asCASH = CASH;

void f() {}

int randomminmax(int min, int max) {
	return Tools::random(min, max);
}

int randomnumber(int n) {
	return Tools::random(n);
}

void MessageCallback(const asSMessageInfo *msg, void *param) {
	const char *type = "Error";
	if (msg->type == asMSGTYPE_WARNING )
		type = "Warning";
	else if (msg->type == asMSGTYPE_INFORMATION ) 
		type = "Info";
	printf("%s (%d, %d) : %s : %s\n", msg->section, msg->row, msg->col, type, msg->message);
}

int AngelScriptEngine::Initialize() {
	pScriptEngine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
	if (pScriptEngine == 0) {
		cout << "Failed to create script engine." << endl;
		return -1;
	}

	int r;
	
	RegisterScriptArray(pScriptEngine, true);
	RegisterScriptString(pScriptEngine);

	// Defenitions
	r = pScriptEngine->RegisterGlobalProperty("const int YES", (void*)&tr); assert( r >= 0 );
	r = pScriptEngine->RegisterGlobalProperty("const int NO", (void*)&fa); assert( r >= 0 );
	r = pScriptEngine->RegisterGlobalProperty("const int ACCEPT", (void*)&tr); assert( r >= 0 );
	r = pScriptEngine->RegisterGlobalProperty("const int DECLINE", (void*)&fa); assert( r >= 0 );
	r = pScriptEngine->RegisterGlobalProperty("const int EQUIP", (void*)&asEQUIP); assert( r >= 0 );
	r = pScriptEngine->RegisterGlobalProperty("const int USE", (void*)&asUSE); assert( r >= 0 );
	r = pScriptEngine->RegisterGlobalProperty("const int SETUP", (void*)&asSETUP); assert( r >= 0 );
	r = pScriptEngine->RegisterGlobalProperty("const int ETC", (void*)&asETC); assert( r >= 0 );
	r = pScriptEngine->RegisterGlobalProperty("const int CASH", (void*)&asCASH); assert( r >= 0 );

	r = pScriptEngine->RegisterObjectType("Position", sizeof(Position), asOBJ_VALUE | asOBJ_POD | asOBJ_APP_CLASS); assert( r >= 0 );
	r = pScriptEngine->RegisterObjectProperty("Position", "int16 x", offsetof(Position,x)); assert( r >= 0 );
	r = pScriptEngine->RegisterObjectProperty("Position", "int16 y", offsetof(Position,y)); assert( r >= 0 );

	// Register Objects

	// Map
	r = pScriptEngine->RegisterObjectType("Map", sizeof(Map), asOBJ_REF ); assert( r >= 0);

	r = pScriptEngine->RegisterObjectBehaviour("Map", asBEHAVE_ADDREF, "void f()", asFUNCTION(f), asCALL_CDECL_OBJLAST); assert( r >= 0);
	r = pScriptEngine->RegisterObjectBehaviour("Map", asBEHAVE_RELEASE, "void f()", asFUNCTION(f), asCALL_CDECL_OBJLAST); assert( r >= 0);

	// Player
	r = pScriptEngine->RegisterObjectType("Player", sizeof(Player), asOBJ_REF ); assert( r >= 0);

	r = pScriptEngine->RegisterObjectBehaviour("Player", asBEHAVE_ADDREF, "void f()", asFUNCTION(f), asCALL_CDECL_OBJLAST); assert( r >= 0);
	r = pScriptEngine->RegisterObjectBehaviour("Player", asBEHAVE_RELEASE, "void f()", asFUNCTION(f), asCALL_CDECL_OBJLAST); assert( r >= 0);

	// Players
	r = pScriptEngine->RegisterObjectType("Players", sizeof(Players), asOBJ_REF ); assert( r >= 0);

	r = pScriptEngine->RegisterObjectBehaviour("Players", asBEHAVE_ADDREF, "void f()", asFUNCTION(f), asCALL_CDECL_OBJLAST); assert( r >= 0);
	r = pScriptEngine->RegisterObjectBehaviour("Players", asBEHAVE_RELEASE, "void f()", asFUNCTION(f), asCALL_CDECL_OBJLAST); assert( r >= 0);

	// NPC
	r = pScriptEngine->RegisterObjectType("NPC", sizeof(PlayerNPC), asOBJ_REF ); assert( r >= 0);

	r = pScriptEngine->RegisterObjectBehaviour("NPC", asBEHAVE_ADDREF, "void f()", asFUNCTION(f), asCALL_CDECL_OBJLAST); assert( r >= 0);
	r = pScriptEngine->RegisterObjectBehaviour("NPC", asBEHAVE_RELEASE, "void f()", asFUNCTION(f), asCALL_CDECL_OBJLAST); assert( r >= 0);

	// Mob
	r = pScriptEngine->RegisterObjectType("Mob", sizeof(Mob), asOBJ_REF ); assert( r >= 0);

	r = pScriptEngine->RegisterObjectBehaviour("Mob", asBEHAVE_ADDREF, "void f()", asFUNCTION(f), asCALL_CDECL_OBJLAST); assert( r >= 0);
	r = pScriptEngine->RegisterObjectBehaviour("Mob", asBEHAVE_RELEASE, "void f()", asFUNCTION(f), asCALL_CDECL_OBJLAST); assert( r >= 0);

	// Reactor
	r = pScriptEngine->RegisterObjectType("Reactor", sizeof(Reactor), asOBJ_REF ); assert( r >= 0);

	r = pScriptEngine->RegisterObjectBehaviour("Reactor", asBEHAVE_ADDREF, "void f()", asFUNCTION(f), asCALL_CDECL_OBJLAST); assert( r >= 0);
	r = pScriptEngine->RegisterObjectBehaviour("Reactor", asBEHAVE_RELEASE, "void f()", asFUNCTION(f), asCALL_CDECL_OBJLAST); assert( r >= 0);

	// Channel
	r = pScriptEngine->RegisterObjectType("Channel", sizeof(Channel), asOBJ_REF ); assert( r >= 0);

	r = pScriptEngine->RegisterObjectBehaviour("Channel", asBEHAVE_ADDREF, "void f()", asFUNCTION(f), asCALL_CDECL_OBJLAST); assert( r >= 0);
	r = pScriptEngine->RegisterObjectBehaviour("Channel", asBEHAVE_RELEASE, "void f()", asFUNCTION(f), asCALL_CDECL_OBJLAST); assert( r >= 0);

	// Portal
	r = pScriptEngine->RegisterObjectType("Portal", sizeof(MapPortalData), asOBJ_REF ); assert( r >= 0);

	r = pScriptEngine->RegisterObjectBehaviour("Portal", asBEHAVE_ADDREF, "void f()", asFUNCTION(f), asCALL_CDECL_OBJLAST); assert( r >= 0);
	r = pScriptEngine->RegisterObjectBehaviour("Portal", asBEHAVE_RELEASE, "void f()", asFUNCTION(f), asCALL_CDECL_OBJLAST); assert( r >= 0);

	// Party
	r = pScriptEngine->RegisterObjectType("Party", sizeof(Party), asOBJ_REF ); assert( r >= 0);

	r = pScriptEngine->RegisterObjectBehaviour("Party", asBEHAVE_ADDREF, "void f()", asFUNCTION(f), asCALL_CDECL_OBJLAST); assert( r >= 0);
	r = pScriptEngine->RegisterObjectBehaviour("Party", asBEHAVE_RELEASE, "void f()", asFUNCTION(f), asCALL_CDECL_OBJLAST); assert( r >= 0);

	// Event
	r = pScriptEngine->RegisterObjectType("Event", sizeof(Event), asOBJ_REF ); assert( r >= 0);

	r = pScriptEngine->RegisterObjectBehaviour("Event", asBEHAVE_ADDREF, "void f()", asFUNCTION(f), asCALL_CDECL_OBJLAST); assert( r >= 0);
	r = pScriptEngine->RegisterObjectBehaviour("Event", asBEHAVE_RELEASE, "void f()", asFUNCTION(f), asCALL_CDECL_OBJLAST); assert( r >= 0);

	// Guilds
	r = pScriptEngine->RegisterObjectType("Guild", sizeof(Guild), asOBJ_REF ); assert(r >= 0);

	r = pScriptEngine->RegisterObjectBehaviour("Guild", asBEHAVE_ADDREF, "void f()", asFUNCTION(f), asCALL_CDECL_OBJLAST); assert(r >= 0);
	r = pScriptEngine->RegisterObjectBehaviour("Guild", asBEHAVE_RELEASE, "void f()", asFUNCTION(f), asCALL_CDECL_OBJLAST); assert(r >= 0);


	// Quest
	r = pScriptEngine->RegisterObjectType("Quest", sizeof(Quest), asOBJ_REF ); assert(r >= 0);

	r = pScriptEngine->RegisterObjectBehaviour("Quest", asBEHAVE_ADDREF, "void f()", asFUNCTION(f), asCALL_CDECL_OBJLAST); assert(r >= 0);
	r = pScriptEngine->RegisterObjectBehaviour("Quest", asBEHAVE_RELEASE, "void f()", asFUNCTION(f), asCALL_CDECL_OBJLAST); assert(r >= 0);

	r = pScriptEngine->RegisterGlobalFunction("int random(int, int)", asFUNCTION(randomminmax), asCALL_CDECL); assert( r >= 0);
	r = pScriptEngine->RegisterGlobalFunction("int random(int)", asFUNCTION(randomnumber), asCALL_CDECL); assert( r >= 0);
	r = pScriptEngine->RegisterGlobalFunction("int getMinute()", asFUNCTION(Tools::getMinute), asCALL_CDECL); assert( r >= 0);

	// Map functions

	r = pScriptEngine->RegisterObjectMethod("Map","Mob@ spawnMob(int, int, int)", asMETHOD(Map, spawnMob), asCALL_THISCALL); assert( r >= 0);
	r = pScriptEngine->RegisterObjectMethod("Map","Reactor@ spawnReactor(int, int, int)", asMETHOD(Map, spawnReactor), asCALL_THISCALL); assert( r >= 0);
	r = pScriptEngine->RegisterObjectMethod("Map","void killMob(Mob@)", asMETHOD(Map, killMob), asCALL_THISCALL); assert( r >= 0);
	r = pScriptEngine->RegisterObjectMethod("Map","int getMobsCount()", asMETHOD(Map, getMobsCount), asCALL_THISCALL); assert( r >= 0);
	r = pScriptEngine->RegisterObjectMethod("Map","int getID()", asMETHOD(Map, getID), asCALL_THISCALL); assert( r >= 0);
	r = pScriptEngine->RegisterObjectMethod("Map","Reactor@ getReactor(int)", asMETHOD(Map, getReactor), asCALL_THISCALL); assert( r >= 0);
	r = pScriptEngine->RegisterObjectMethod("Map","Mob@ getMob(int)", asMETHOD(Map, getMob), asCALL_THISCALL); assert( r >= 0);
	r = pScriptEngine->RegisterObjectMethod("Map","void destroyReactor(Reactor@)", asMETHOD(Map, destroyReactor), asCALL_THISCALL); assert( r >= 0);
	r = pScriptEngine->RegisterObjectMethod("Map","Reactor@ getReactorByReactorID(int)", asMETHOD(Map, getReactorByReactorID), asCALL_THISCALL); assert( r >= 0);
	r = pScriptEngine->RegisterObjectMethod("Map","void setSpawn(bool)", asMETHOD(Map, setSpawn), asCALL_THISCALL); assert( r >= 0);
	r = pScriptEngine->RegisterObjectMethod("Map","void clearMobs()", asMETHOD(Map, clearMobs), asCALL_THISCALL); assert( r >= 0);
	r = pScriptEngine->RegisterObjectMethod("Map","void clearReactors()", asMETHOD(Map, clearReactors), asCALL_THISCALL); assert( r >= 0);
	r = pScriptEngine->RegisterObjectMethod("Map","void clearDrops()", asMETHOD(Map, clearDrops), asCALL_THISCALL); assert( r >= 0);
	r = pScriptEngine->RegisterObjectMethod("Map","void clear()", asMETHOD(Map, clear), asCALL_THISCALL); assert( r >= 0);
	r = pScriptEngine->RegisterObjectMethod("Map","void setShip(bool)",asMETHOD(Map, setShip), asCALL_THISCALL); assert (r >= 0);
	r = pScriptEngine->RegisterObjectMethod("Map","bool getShip()",asMETHOD(Map, getShip), asCALL_THISCALL); assert (r >= 0);
	r = pScriptEngine->RegisterObjectMethod("Map","Players@ getPlayers()", asMETHOD(Map, getPlayers), asCALL_THISCALL); assert( r >= 0);
	r = pScriptEngine->RegisterObjectMethod("Map","Event@ getEvent()", asMETHOD(Map, getEvent), asCALL_THISCALL); assert( r >= 0);
	r = pScriptEngine->RegisterObjectMethod("Map","Channel@ getChannel()", asMETHOD(Map, getChannel), asCALL_THISCALL); assert( r >= 0);
	r = pScriptEngine->RegisterObjectMethod("Map","void showMessage(string&)", asMETHOD(Map, showMessage), asCALL_THISCALL); assert( r >= 0);
	r = pScriptEngine->RegisterObjectMethod("Map","void changeMusic(string&)", asMETHOD(Map, changeMusic), asCALL_THISCALL); assert( r >= 0);
	r = pScriptEngine->RegisterObjectMethod("Map","string& getMusic()", asMETHOD(Map, getMusic), asCALL_THISCALL); assert( r >= 0);
	r = pScriptEngine->RegisterObjectMethod("Map","void showEffect(string&)", asMETHOD(Map, showEffect), asCALL_THISCALL); assert( r >= 0);
	r = pScriptEngine->RegisterObjectMethod("Map","void playSound(string&)", asMETHOD(Map, playSound), asCALL_THISCALL); assert( r >= 0);
	r = pScriptEngine->RegisterObjectMethod("Map","void showObject(string&)", asMETHOD(Map, showObject), asCALL_THISCALL); assert( r >= 0);

	// Event functions

	r = pScriptEngine->RegisterObjectMethod("Event","Players@ getPlayers()", asMETHOD(Event, getPlayers), asCALL_THISCALL);    assert( r >= 0);

	// Player functions

	r = pScriptEngine->RegisterObjectMethod("Player","Position getPosition()", asMETHOD(Player, getPosition), asCALL_THISCALL); assert( r >= 0);
	r = pScriptEngine->RegisterObjectMethod("Player","int16 getFoothold()", asMETHOD(Player, getFoothold), asCALL_THISCALL);	 assert( r >= 0) ;
	r = pScriptEngine->RegisterObjectMethod("Player","int getID()", asMETHOD(Player, getID), asCALL_THISCALL); assert( r >= 0);
	r = pScriptEngine->RegisterObjectMethod("Player","void changeMap(int)", asMETHOD(Player, setMap), asCALL_THISCALL); assert( r >= 0);
	r = pScriptEngine->RegisterObjectMethod("Player","void changeMap(int, int)", asMETHOD(Player, setMapPos), asCALL_THISCALL); assert( r >= 0);
	r = pScriptEngine->RegisterObjectMethod("Player","void changeMap(int, string&)", asMETHOD(Player, setMapPortal), asCALL_THISCALL); assert( r >= 0);
	r = pScriptEngine->RegisterObjectMethod("Player","int getItemAmount(int)", asMETHOD(Player, getItemAmount), asCALL_THISCALL); assert( r >= 0);
	r = pScriptEngine->RegisterObjectMethod("Player","int getMesos()", asMETHOD(Player, getMesos), asCALL_THISCALL); assert( r >= 0);
	r = pScriptEngine->RegisterObjectMethod("Player","int getPaypalnx()", asMETHOD(Player, getPaypalnx), asCALL_THISCALL); assert( r >= 0);
	r = pScriptEngine->RegisterObjectMethod("Player","void setPaypalnx(int16)", asMETHOD(Player, setPaypalnx), asCALL_THISCALL); assert( r >= 0);
	r = pScriptEngine->RegisterObjectMethod("Player","int getMaplePoints()", asMETHOD(Player, getMaplePoints), asCALL_THISCALL); assert( r >= 0);
	r = pScriptEngine->RegisterObjectMethod("Player","void setMaplePoints(int16)", asMETHOD(Player, setMaplePoints), asCALL_THISCALL); assert( r >= 0);
	r = pScriptEngine->RegisterObjectMethod("Player","int getCardnx()", asMETHOD(Player, getCardnx), asCALL_THISCALL); assert( r >= 0);
	r = pScriptEngine->RegisterObjectMethod("Player","void setCardnx(int16)", asMETHOD(Player, setCardnx), asCALL_THISCALL); assert( r >= 0);
	r = pScriptEngine->RegisterObjectMethod("Player","bool giveItem(int, int16)", asMETHOD(Player, giveItem), asCALL_THISCALL); assert( r >= 0);
	r = pScriptEngine->RegisterObjectMethod("Player","void giveMesos(int)", asMETHOD(Player, giveMesos), asCALL_THISCALL); assert( r >= 0);
	r = pScriptEngine->RegisterObjectMethod("Player","Map@ getMap()", asMETHOD(Player, getMap), asCALL_THISCALL); assert( r >= 0);
	r = pScriptEngine->RegisterObjectMethod("Player","void setStyle(int)", asMETHOD(Player, setStyle), asCALL_THISCALL); assert( r >= 0);
	r = pScriptEngine->RegisterObjectMethod("Player","void giveExp(int)", asMETHOD(Player, giveExp), asCALL_THISCALL); assert( r >= 0);
	r = pScriptEngine->RegisterObjectMethod("Player","uint8 getLevel()", asMETHOD(Player, getLevel), asCALL_THISCALL); assert( r >= 0);
	r = pScriptEngine->RegisterObjectMethod("Player","int16 getJob()", asMETHOD(Player, getJob), asCALL_THISCALL); assert( r >= 0);
	r = pScriptEngine->RegisterObjectMethod("Player","void setJob(int16)", asMETHOD(Player, setJobS), asCALL_THISCALL); assert( r >= 0);
	r = pScriptEngine->RegisterObjectMethod("Player","int getHair()", asMETHOD(Player, getHair), asCALL_THISCALL); assert( r >= 0);
	r = pScriptEngine->RegisterObjectMethod("Player","int getFace()", asMETHOD(Player, getFace), asCALL_THISCALL); assert( r >= 0);
	r = pScriptEngine->RegisterObjectMethod("Player","void setMaxHp(int16)", asMETHOD(Player, setMaxHpS), asCALL_THISCALL); assert( r >= 0);
	r = pScriptEngine->RegisterObjectMethod("Player","uint16 getMaxHp()", asMETHOD(Player, getMaxHp), asCALL_THISCALL); assert( r >= 0);
	r = pScriptEngine->RegisterObjectMethod("Player","void setMaxMp(int16)", asMETHOD(Player, setMaxMpS), asCALL_THISCALL); assert( r >= 0);
	r = pScriptEngine->RegisterObjectMethod("Player","uint16 getMaxMp()", asMETHOD(Player, getMaxMp), asCALL_THISCALL); assert( r >= 0);
	r = pScriptEngine->RegisterObjectMethod("Player","void setHp(int16)", asMETHOD(Player, setHpS), asCALL_THISCALL); assert( r >= 0);
	r = pScriptEngine->RegisterObjectMethod("Player","uint16 getHp()", asMETHOD(Player, getHp), asCALL_THISCALL); assert( r >= 0);
	r = pScriptEngine->RegisterObjectMethod("Player","void setMp(int16)", asMETHOD(Player, setMpS), asCALL_THISCALL); assert( r >= 0);
	r = pScriptEngine->RegisterObjectMethod("Player","uint16 getMp()", asMETHOD(Player, getMp), asCALL_THISCALL); assert( r >= 0);
	r = pScriptEngine->RegisterObjectMethod("Player","void setAp(int16)", asMETHOD(Player, setApS), asCALL_THISCALL); assert( r >= 0);
	r = pScriptEngine->RegisterObjectMethod("Player","void setSp(int16)", asMETHOD(Player, setSpS), asCALL_THISCALL); assert( r >= 0);
	r = pScriptEngine->RegisterObjectMethod("Player","void setStr(int16)", asMETHOD(Player, setStrS), asCALL_THISCALL); assert( r >= 0);
	r = pScriptEngine->RegisterObjectMethod("Player","void setDex(int16)", asMETHOD(Player, setDexS), asCALL_THISCALL); assert( r >= 0);
	r = pScriptEngine->RegisterObjectMethod("Player","void setInt(int16)", asMETHOD(Player, setIntS), asCALL_THISCALL); assert( r >= 0);
	r = pScriptEngine->RegisterObjectMethod("Player","void setLuk(int16)", asMETHOD(Player, setLukS), asCALL_THISCALL); assert( r >= 0);
	r = pScriptEngine->RegisterObjectMethod("Player","int16 getAp()", asMETHOD(Player, getAp), asCALL_THISCALL); assert( r >= 0);
	r = pScriptEngine->RegisterObjectMethod("Player","int16 getSp()", asMETHOD(Player, getSp), asCALL_THISCALL); assert( r >= 0);
	r = pScriptEngine->RegisterObjectMethod("Player","int16 getStr()", asMETHOD(Player, getStr), asCALL_THISCALL); assert( r >= 0);
	r = pScriptEngine->RegisterObjectMethod("Player","int16 getDex()", asMETHOD(Player, getDex), asCALL_THISCALL); assert( r >= 0);
	r = pScriptEngine->RegisterObjectMethod("Player","int16 getInt()", asMETHOD(Player, getInt), asCALL_THISCALL); assert( r >= 0);
	r = pScriptEngine->RegisterObjectMethod("Player","int16 getLuk()", asMETHOD(Player, getLuk), asCALL_THISCALL); assert( r >= 0);
	r = pScriptEngine->RegisterObjectMethod("Player","Channel@ getChannel()", asMETHOD(Player, getChannel), asCALL_THISCALL); assert( r >= 0);
	r = pScriptEngine->RegisterObjectMethod("Player","void setVariable(string&, int)", asMETHOD(Player, setVariable), asCALL_THISCALL); assert( r >= 0);
	r = pScriptEngine->RegisterObjectMethod("Player","int getVariable(string&)", asMETHOD(Player, getVariable), asCALL_THISCALL); assert( r >= 0);
	r = pScriptEngine->RegisterObjectMethod("Player","void deleteVariable(string&)", asMETHOD(Player, deleteVariable), asCALL_THISCALL); assert( r >= 0);
	r = pScriptEngine->RegisterObjectMethod("Player","void setEvent(string&)", asMETHOD(Player, setEvent), asCALL_THISCALL); assert( r >= 0);
	r = pScriptEngine->RegisterObjectMethod("Player","Party@ getParty()", asMETHOD(Player, getParty), asCALL_THISCALL); assert( r >= 0);
	r = pScriptEngine->RegisterObjectMethod("Player","bool checkSlot(int)", asMETHOD(Player, checkSlot), asCALL_THISCALL); assert( r >= 0);
	r = pScriptEngine->RegisterObjectMethod("Player","uint8 getGender()", asMETHOD(Player, getGender), asCALL_THISCALL); assert( r >= 0);
	r = pScriptEngine->RegisterObjectMethod("Player","Guild@ getGuild()", asMETHOD(Player, getGuild), asCALL_THISCALL); assert(r >= 0);
	r = pScriptEngine->RegisterObjectMethod("Player","int getGuildRank()", asMETHOD(Player, getGuildRank), asCALL_THISCALL); assert(r >= 0);
	r = pScriptEngine->RegisterObjectMethod("Player","string& getName()", asMETHOD(Player, getName), asCALL_THISCALL); assert(r >= 0);
	r = pScriptEngine->RegisterObjectMethod("Player","bool isGM()", asMETHOD(Player, isGM), asCALL_THISCALL); assert(r >= 0);
	r = pScriptEngine->RegisterObjectMethod("Player","void showMessage(string&)", asMETHOD(Player, showMessage), asCALL_THISCALL); assert(r >= 0);
	r = pScriptEngine->RegisterObjectMethod("Player","void showInstructionBubble(string&, int16, int16)", asMETHOD(Player, showInstructionBubble), asCALL_THISCALL); assert(r >= 0);
	r = pScriptEngine->RegisterObjectMethod("Player","void showMimo(bool)", asMETHOD(Player, showMimo), asCALL_THISCALL); assert(r >= 0);
	r = pScriptEngine->RegisterObjectMethod("Player","void mimoTalk(string&, int32, int32)", asMETHOD(Player, mimoTalk), asCALL_THISCALL); assert(r >= 0);
	r = pScriptEngine->RegisterObjectMethod("Player","void dojoWarpUp()", asMETHOD(Player, dojoWarpUp), asCALL_THISCALL); assert(r >= 0);
	r = pScriptEngine->RegisterObjectMethod("Player","void dojoAnimation()", asMETHOD(Player, dojoAnimation), asCALL_THISCALL); assert(r >= 0);
	r = pScriptEngine->RegisterObjectMethod("Player","int16 getQuest(int16)", asMETHOD(Player, getQuest), asCALL_THISCALL); assert( r >= 0);
	r = pScriptEngine->RegisterObjectMethod("Player","void sendNpc(int)", asMETHOD(Player, sendNpc), asCALL_THISCALL); assert(r >= 0);

	// Players functions

	r = pScriptEngine->RegisterObjectMethod("Players","void changeMap(int)", asMETHOD(Players, changeMap), asCALL_THISCALL); assert( r >= 0);
	r = pScriptEngine->RegisterObjectMethod("Players","int getAmount()", asMETHOD(Players, getPlayersCount), asCALL_THISCALL); assert( r >= 0);
	r = pScriptEngine->RegisterObjectMethod("Players", "Player@ opIndex(int)", asMETHOD(Players, operator[]), asCALL_THISCALL); assert( r >= 0 );

	// Mob object

	r = pScriptEngine->RegisterObjectMethod("Mob","int getID()", asMETHOD(Mob, getID), asCALL_THISCALL); assert( r >= 0);
	r = pScriptEngine->RegisterObjectMethod("Mob","int getMobID()", asMETHOD(Mob, getMobId), asCALL_THISCALL); assert( r >= 0);

	// Channel object

	r = pScriptEngine->RegisterObjectMethod("Channel","Map@ getMap(int)", asMETHOD(Channel, getMap), asCALL_THISCALL); assert( r >= 0);
	r = pScriptEngine->RegisterObjectMethod("Channel","int getID()", asMETHOD(Channel, getID), asCALL_THISCALL); assert( r >= 0);
	r = pScriptEngine->RegisterObjectMethod("Channel","bool createEvent(string&, Player@)", asMETHOD(Channel, createEventForPlayer), asCALL_THISCALL); assert( r >= 0);
	r = pScriptEngine->RegisterObjectMethod("Channel","bool createEvent(string&, Players@)", asMETHOD(Channel, createEventForPlayers), asCALL_THISCALL); assert( r >= 0);
	r = pScriptEngine->RegisterObjectMethod("Channel","bool createEvent(string&, Party@)", asMETHOD(Channel, createEventForParty), asCALL_THISCALL); assert( r >= 0);
	r = pScriptEngine->RegisterObjectMethod("Channel","bool createEvent(string&)", asMETHOD(Channel, createEvent), asCALL_THISCALL); assert( r >= 0);
	r = pScriptEngine->RegisterObjectMethod("Channel","void deleteEvent(string&)", asMETHOD(Channel, deleteEvent), asCALL_THISCALL); assert( r >= 0);
	r = pScriptEngine->RegisterObjectMethod("Channel","bool deleteEvent(string&, Player@)", asMETHOD(Channel, deleteEventForPlayer), asCALL_THISCALL); assert( r >= 0);
	r = pScriptEngine->RegisterObjectMethod("Channel","bool isEventActive(string&)", asMETHOD(Channel, isEventActive), asCALL_THISCALL); assert( r >= 0);

	// Portal object

	r = pScriptEngine->RegisterObjectMethod("Portal","int getID()", asMETHOD(MapPortalData, getID), asCALL_THISCALL); assert( r >= 0);

	// NPC object

	r = pScriptEngine->RegisterObjectMethod("NPC","void addText(string&)", asMETHOD(PlayerNPC, addText), asCALL_THISCALL); assert( r >= 0);
	r = pScriptEngine->RegisterObjectMethod("NPC","void sendSimple()", asMETHOD(PlayerNPC, sendSimple), asCALL_THISCALL); assert( r >= 0);
	r = pScriptEngine->RegisterObjectMethod("NPC","void sendYesNo()", asMETHOD(PlayerNPC, sendYesNo), asCALL_THISCALL); assert( r >= 0);
	r = pScriptEngine->RegisterObjectMethod("NPC","void sendNext()", asMETHOD(PlayerNPC, sendNext), asCALL_THISCALL); assert( r >= 0);
	r = pScriptEngine->RegisterObjectMethod("NPC","void sendBackNext()", asMETHOD(PlayerNPC, sendBackNext), asCALL_THISCALL); assert( r >= 0);
	r = pScriptEngine->RegisterObjectMethod("NPC","void sendBackOK()", asMETHOD(PlayerNPC, sendBackOK), asCALL_THISCALL); assert( r >= 0);
	r = pScriptEngine->RegisterObjectMethod("NPC","void sendOK()", asMETHOD(PlayerNPC, sendOK), asCALL_THISCALL); assert( r >= 0);
	r = pScriptEngine->RegisterObjectMethod("NPC","void sendAcceptDecline()", asMETHOD(PlayerNPC, sendAcceptDecline), asCALL_THISCALL); assert( r >= 0);
	r = pScriptEngine->RegisterObjectMethod("NPC","void sendGetNumber(int, int, int)", asMETHOD(PlayerNPC, sendGetNumber), asCALL_THISCALL); assert( r >= 0);
	r = pScriptEngine->RegisterObjectMethod("NPC","void sendStyle(int[]&)", asMETHOD(PlayerNPC, sendStyle), asCALL_THISCALL); assert( r >= 0);
	r = pScriptEngine->RegisterObjectMethod("NPC","int getState()", asMETHOD(PlayerNPC, getState), asCALL_THISCALL); assert( r >= 0);
	r = pScriptEngine->RegisterObjectMethod("NPC","int getSelected()", asMETHOD(PlayerNPC, getSelected), asCALL_THISCALL); assert( r >= 0);
	r = pScriptEngine->RegisterObjectMethod("NPC","void setState(int)", asMETHOD(PlayerNPC, setState), asCALL_THISCALL); assert( r >= 0);
	r = pScriptEngine->RegisterObjectMethod("NPC","void setSelected(int)", asMETHOD(PlayerNPC, setSelected), asCALL_THISCALL); assert( r >= 0);
	r = pScriptEngine->RegisterObjectMethod("NPC","void setGetNumber(int)", asMETHOD(PlayerNPC, setGetNumber), asCALL_THISCALL); assert( r >= 0);
	r = pScriptEngine->RegisterObjectMethod("NPC","int getNumber()", asMETHOD(PlayerNPC, getNumber), asCALL_THISCALL); assert( r >= 0);
	r = pScriptEngine->RegisterObjectMethod("NPC","void setGetSaveInt(int)", asMETHOD(PlayerNPC, setGetSaveInt), asCALL_THISCALL); assert( r >= 0);
	r = pScriptEngine->RegisterObjectMethod("NPC","int getSaveInt()", asMETHOD(PlayerNPC, getSaveInt), asCALL_THISCALL); assert( r >= 0);
	r = pScriptEngine->RegisterObjectMethod("NPC","void end()", asMETHOD(PlayerNPC, end), asCALL_THISCALL); assert( r >= 0);
	r = pScriptEngine->RegisterObjectMethod("NPC","void setVariable(string&, int)", asMETHOD(PlayerNPC, setVariable), asCALL_THISCALL); assert( r >= 0);
	r = pScriptEngine->RegisterObjectMethod("NPC","int getVariable(string&)", asMETHOD(PlayerNPC, getVariable), asCALL_THISCALL); assert( r >= 0);
	r = pScriptEngine->RegisterObjectMethod("NPC","Player@ getPlayer()", asMETHOD(PlayerNPC, getPlayer), asCALL_THISCALL); assert( r >= 0); // to be removed
	r = pScriptEngine->RegisterObjectMethod("NPC","void addQuest(int16)", asMETHOD(PlayerNPC, addQuest), asCALL_THISCALL); assert( r >= 0);
	r = pScriptEngine->RegisterObjectMethod("NPC","void endQuest(int16)", asMETHOD(PlayerNPC, endQuest), asCALL_THISCALL); assert( r >= 0);
	r = pScriptEngine->RegisterObjectMethod("NPC","void createGuild()", asMETHOD(PlayerNPC, createGuild), asCALL_THISCALL); assert(r >= 0);
	r = pScriptEngine->RegisterObjectMethod("NPC","void changeGuildEmblem()", asMETHOD(PlayerNPC, changeGuildEmblem), asCALL_THISCALL); assert(r >= 0);
	r = pScriptEngine->RegisterObjectMethod("NPC","void disbandGuild()", asMETHOD(PlayerNPC, disbandGuild), asCALL_THISCALL); assert(r >= 0);
	r = pScriptEngine->RegisterObjectMethod("NPC","void increaseGuildCapacity()", asMETHOD(PlayerNPC, increaseGuildCapacity), asCALL_THISCALL); assert(r >= 0);

	// Reactor object

	r = pScriptEngine->RegisterObjectMethod("Reactor","Map@ getMap()", asMETHOD(Reactor, getMap), asCALL_THISCALL); assert( r >= 0);
	r = pScriptEngine->RegisterObjectMethod("Reactor","int getState()", asMETHOD(Reactor, getState), asCALL_THISCALL); assert( r >= 0);
	r = pScriptEngine->RegisterObjectMethod("Reactor","void setState(int)", asMETHOD(Reactor, setState), asCALL_THISCALL); assert( r >= 0);
	r = pScriptEngine->RegisterObjectMethod("Reactor","Position getPosition()", asMETHOD(Reactor, getPosition), asCALL_THISCALL); assert( r >= 0);
	r = pScriptEngine->RegisterObjectMethod("Reactor","int getID()", asMETHOD(Reactor, getID), asCALL_THISCALL); assert( r >= 0);
	r = pScriptEngine->RegisterObjectMethod("Reactor","int getReactorID()", asMETHOD(Reactor, getReactorID), asCALL_THISCALL); assert( r >= 0);

	// Party object

	r = pScriptEngine->RegisterObjectMethod("Party","int getLeader()", asMETHOD(Party, getLeader), asCALL_THISCALL); assert( r >= 0);
	r = pScriptEngine->RegisterObjectMethod("Party","Players@ getMembers()", asMETHOD(Party, getMembers), asCALL_THISCALL); assert( r >= 0);
	r = pScriptEngine->RegisterObjectMethod("Party","void setVariable(string&, int)", asMETHOD(Party, setVariable), asCALL_THISCALL); assert( r >= 0);
	r = pScriptEngine->RegisterObjectMethod("Party","int getVariable(string&)", asMETHOD(Party, getVariable), asCALL_THISCALL); assert( r >= 0);
	r = pScriptEngine->RegisterObjectMethod("Party","void deleteVariable(string&)", asMETHOD(Party, deleteVariable), asCALL_THISCALL); assert( r >= 0);

	// Guild object

	r = pScriptEngine->RegisterObjectMethod("Guild","int getID()", asMETHOD(Guild, getID), asCALL_THISCALL); assert(r >= 0);
	r = pScriptEngine->RegisterObjectMethod("Guild","int8 getCapacity()", asMETHOD(Guild, getCapacity), asCALL_THISCALL); assert(r >= 0);

	// Skill

	r = pScriptEngine->RegisterObjectType("Skill", sizeof(Skill), asOBJ_REF ); assert( r >= 0);
	r = pScriptEngine->RegisterObjectBehaviour("Skill", asBEHAVE_ADDREF, "void f()", asFUNCTION(f), asCALL_CDECL_OBJLAST); assert( r >= 0);
	r = pScriptEngine->RegisterObjectBehaviour("Skill", asBEHAVE_RELEASE, "void f()", asFUNCTION(f), asCALL_CDECL_OBJLAST); assert( r >= 0);

	// Additional Player and Skill functions

	r = pScriptEngine->RegisterObjectMethod("Player","Skill@ getSkill(int)", asMETHOD(Player, getSkill), asCALL_THISCALL); assert( r >= 0);
	r = pScriptEngine->RegisterObjectMethod("Player","Skill@ maxSkill(int)", asMETHOD(Player, maxSkill), asCALL_THISCALL); assert( r >= 0);
	r = pScriptEngine->RegisterObjectMethod("Skill","int getID()", asMETHOD(Skill, getID), asCALL_THISCALL); assert( r >= 0);
	r = pScriptEngine->RegisterObjectMethod("Skill","int getLevel()", asMETHOD(Skill, getLevel), asCALL_THISCALL); assert( r >= 0);
	r = pScriptEngine->RegisterObjectMethod("Skill","int getMasterLevel()", asMETHOD(Skill, getMasterLevel), asCALL_THISCALL); assert( r >= 0);

	pScriptEngine->SetMessageCallback(asFUNCTION(MessageCallback), 0, asCALL_CDECL);

	return 1;
}

int AngelScriptEngine::LoadScript(asIScriptEngine * pScriptEngine, const char *filename, const char * module) {
	FILE* pFile;
	fopen_s(&pFile, filename, "rb");
	if (pFile == 0) {
		return -1;
	}

	fseek(pFile, 0, SEEK_END);
	int len = ftell(pFile);
	fseek(pFile, 0, SEEK_SET);

	std::string code;
	code.resize(len);

	size_t c = fread(&code[0], len, 1, pFile);
	fclose(pFile);

	if (c == 0)  {
		return -1;
	}
	int nRet = pScriptEngine->GetModule(module, asGM_ALWAYS_CREATE)->AddScriptSection(filename, code.c_str(), len, 0);
	if (nRet < 0) {
		cout << "An error occured while adding the script section." << endl;
	}
	return nRet;
}

ByteCodeMemory<string>* AngelScriptEngine::loadPortal(string id) {
	char name[100];
	sprintf_s(name, 100, "Scripts/Portals/%s.as", (char*)id.c_str());
	if(LoadScript(pScriptEngine, name, name) < 0) {
		cout << "Failed to load script: " << name << endl;
		return 0;
	}
	if (pScriptEngine->GetModule(name)->Build() < 0) {
		cout << "Failed to compile script: " << name << endl;
		return 0;
	}
	ByteCodeMemory<string>* st = new ByteCodeMemory<string>(id, name);
	//PortalsData::getInstance()->add(st);
	return st;
}

ByteCodeMemory<string>* AngelScriptEngine::loadChannelEvent(string id){
	char name[100];
	sprintf_s(name, 100, "Scripts/ChannelEvents/%s.as", (char*)id.c_str());
	if(LoadScript(pScriptEngine, name, name) < 0) {
		cout << "Failed to load script: " << name << endl;
		return 0;
	}
	if (pScriptEngine->GetModule(name)->Build() < 0) {
		cout << "Failed to compile script: " << name << endl;
		return 0;
	}
	ByteCodeMemory<string>* st = new ByteCodeMemory<string>(id, name);
	//ChannelEventsScriptsData::getInstance()->add(st);
	return st;
}

ByteCodeMemory<int>* AngelScriptEngine::loadReactor(int id) {
	char name[100];
	sprintf_s(name, 100, "Scripts/Reactors/%d.as", id);
	if(LoadScript(pScriptEngine, name, name) < 0) {
		cout << "Failed to load script: " << name << endl;
		return 0;
	}
	if (pScriptEngine->GetModule(name)->Build() < 0) {
		cout << "Failed to compile script: " << name << endl;
		return 0;
	}
	ByteCodeMemory<int>* st = new ByteCodeMemory<int>(id, name);
	//ReactorScriptsData::getInstance()->add(st);
	return st;
}

ByteCodeMemory<int>* AngelScriptEngine::loadNPC(int id) {
	char name[100];
	sprintf_s(name, 100, "Scripts/NPCs/%d.as", id);
	if(LoadScript(pScriptEngine, name, name) < 0) {
		cout << "Failed to load script: " << name << endl;
		return 0;
	}
	if (pScriptEngine->GetModule(name)->Build() < 0) {
		cout << "Failed to compile script: " << name << endl;
		return 0;
	}
	ByteCodeMemory<int>* st = new ByteCodeMemory<int>(id, name);
	//NPCsScriptsData::getInstance()->add(st);
	return st;
}

ByteCodeMemory<int>* AngelScriptEngine::loadQuest(int id) {
	char name[100];
	sprintf_s(name, 100, "Scripts/Quests/%d.as", id);
	if(LoadScript(pScriptEngine, name, name) < 0) {
		cout << "Failed to load script: " << name << endl;
		return 0;
	}
	if (pScriptEngine->GetModule(name)->Build() < 0) {
		cout << "Failed to compile script: " << name << endl;
		return 0;
	}
	ByteCodeMemory<int>* st = new ByteCodeMemory<int>(id, name);
	//NPCsQuestsData::getInstance()->add(st);
	return st;
}

int AngelScriptEngine::handleReactor(Player* player, Reactor* reactor) {
	reactor->drop(player);
	ByteCodeMemory<int>* st = ReactorScriptsData::getInstance()->getDataByID(reactor->getReactorID());
	if(st == 0) {
		cout << "Failed to get data for Reactor: " << reactor->getReactorID() << " in map: " << reactor->getMap()->getID() << endl;
		return 0;
	}
	asIScriptContext *pContext = pScriptEngine->CreateContext();
	if(pContext == 0) {
		cout << "Failed to create the context." << endl;
		pScriptEngine->Release();
		return 0;
	}
	int nFunctionID = -1;
	nFunctionID = pScriptEngine->GetModule(st->getName())->GetFunctionIdByName("reactor");
	if(nFunctionID < 0) {
		return 0;
	}
	pContext->Prepare(nFunctionID);
	pContext->SetArgObject(0, reactor);
	pContext->Execute();
	return 1;
}

int AngelScriptEngine::handleChannelEvent(Channel* channel, string& eventn){
	ByteCodeMemory<string>* st = ChannelEventsScriptsData::getInstance()->getDataByID(eventn);
	if(st == 0) {
		cout << "Failed to get data for channel_event: " << eventn << endl;
		return 0;
	}
	asIScriptContext *pContext = pScriptEngine->CreateContext();
	if(pContext == 0) {
		printf("Failed to create the context.");
		pScriptEngine->Release();
		return 0;
	}
	int nFunctionID = pScriptEngine->GetModule(st->getName())->GetFunctionIdByName("channel_event");
	if(nFunctionID < 0) {
		return 0;
	}
	pContext->Prepare(nFunctionID);
	pContext->SetArgObject(0, channel);
	pContext->Execute();
	return 1;
}

int AngelScriptEngine::handlePortal(Player* player, MapPortalData* portal) {
	ByteCodeMemory<string>* st = PortalsData::getInstance()->getDataByID(portal->getScript());
	if(st == 0) {
		cout << "Failed to get data for Portal: " << portal->getScript() << " in Map: " << player->getMap()->getID() << endl;
		return 0;
	}
	asIScriptContext *pContext = pScriptEngine->CreateContext();
	if(pContext == 0) {
		cout << "Failed to create the context." << endl;
		pScriptEngine->Release();
		return 0;
	}
	int nFunctionID = pScriptEngine->GetModule(st->getName())->GetFunctionIdByName("portal");
	if(nFunctionID < 0) {
		return 0;
	}
	pContext->Prepare(nFunctionID);
	pContext->SetArgObject(0, player);
	pContext->SetArgObject(1, portal);
	pContext->Execute();
	return 1;
}

int AngelScriptEngine::handleNPC(PlayerNPC* npc, bool complete) {
	ByteCodeMemory<int>* st = 0;
	if(npc->getQuestID()) {
		st = NPCsQuestsData::getInstance()->getDataByID(npc->getQuestID());
	} else {
		st = NPCsScriptsData::getInstance()->getDataByID(npc->getNpcID());
	}
	if(st == 0) {
		cout << "Failed to get data for Npc: " << npc->getNpcID() << endl;
		return 0;
	}
	asIScriptContext *pContext = pScriptEngine->CreateContext();
	if(pContext == 0) {
		cout << "Failed to create the context." << endl;
		pScriptEngine->Release();
		return 0;
	}
	int nFunctionID = -1;
	if(npc->getQuestID()) {
		if (complete) {
			nFunctionID = pScriptEngine->GetModule(st->getName())->GetFunctionIdByName("complete_quest");
		} else {
			nFunctionID = pScriptEngine->GetModule(st->getName())->GetFunctionIdByName("start_quest");
		}
	}
	else {
		nFunctionID = pScriptEngine->GetModule(st->getName())->GetFunctionIdByName("npc");
	}
	if(nFunctionID < 0) {
		return 0;
	}
	pContext->Prepare(nFunctionID);
	pContext->SetArgObject(0, npc->getPlayer());
	pContext->SetArgObject(1, npc);

	if(pContext->Execute() !=  asEXECUTION_FINISHED) {
		cout << "Error with executing Npc: " << npc->getNpcID() << endl;
		return 0;
	}
	return 1;
}
